package com.huaxindata.im.model.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.huaxin.common.Global;
import com.huaxindata.im.model.entity.HxAnnoModel;

import org.eclipse.paho.android.service.MqttTraceHandler;

import java.util.Iterator;

public class LocalAnnoStore {

    public static final String CLIENT_ID = ""+ Global.user.getUserId();
    // TAG used for indentify trace data etc.
    private static String TAG = "LocalAnnoStore";

    // the name of the table in the database to which we will save messages
    private static final String ANNO_TABLE_NAME = "LocalAnnoTable";

    // the database
    private SQLiteDatabase db = null;

    // a SQLiteOpenHelper specific for this database
    private MQTTDatabaseHelper annoDb = null;

    // a place to send trace data
    private MqttTraceHandler traceHandler = null;

    private static LocalAnnoStore annoStore;

    /**
     * We need a SQLiteOpenHelper to handle database creation and updating
     */
    private static class MQTTDatabaseHelper extends SQLiteOpenHelper {
        private static final String DATABASE_NAME = "anno.db";
        // database version, used to recognise when we need to upgrade
        // (delete and recreate)
        private static final int DATABASE_VERSION = 7;
        private static final String ID = "bulletinId";
        private static final String TITLE = "title";
        private static final String DESC = "description";
        private static final String CREATER = "creater";
        private static final String DATE = "createDate";
        private static final String READ = "read";
        private static final String RECV = "recv";
        // a place to send trace data
        private MqttTraceHandler traceHandler = null;

        /**
         * Constructor.
         *
         * @param traceHandler
         * @param context
         */
        public MQTTDatabaseHelper(MqttTraceHandler traceHandler, Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            this.traceHandler = traceHandler;
        }

        /**
         * When the database is (re)created, create our table
         *
         * @param database
         */
        @Override
        public void onCreate(SQLiteDatabase database) {
            String createArrivedTableStatement = "CREATE TABLE "
                    + ANNO_TABLE_NAME + "("
                    + ID + " INTEGER PRIMARY KEY, "//ID
                    + TITLE + " TEXT, "//标题
                    + DESC + " TEXT, "//描述
                    + RECV + " TEXT, "//接收者
                    + CREATER + " TEXT, "//发起人
                    + READ + " INTEGER, "//是否已读
                    + DATE + " INTEGER " + ");";//日期
            traceHandler.traceDebug(TAG, "onCreate {"
                    + createArrivedTableStatement + "}");
            try {
                database.execSQL(createArrivedTableStatement);
                traceHandler.traceDebug(TAG, "created the table");
            } catch (SQLException e) {
                traceHandler.traceException(TAG, "onCreate", e);
                throw e;
            }
        }

        /**
         * To upgrade the database, drop and recreate our table
         *
         * @param db         the database
         * @param oldVersion ignored
         * @param newVersion ignored
         */

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            traceHandler.traceDebug(TAG, "onUpgrade");
            try {
                db.execSQL("DROP TABLE IF EXISTS " + ANNO_TABLE_NAME);
            } catch (SQLException e) {
                traceHandler.traceException(TAG, "onUpgrade", e);
                throw e;
            }
            onCreate(db);
            traceHandler.traceDebug(TAG, "onUpgrade complete");
        }
    }

    public static LocalAnnoStore getAnnoStore() {
        if (annoStore==null)
            throw new RuntimeException("you must execute init method first");
        return annoStore;
    }
    public static LocalAnnoStore getAnnoStore(Context context) {
        return getAnnoStore(null, context);
    }

    public static LocalAnnoStore getAnnoStore(MqttTraceHandler traceHandler, Context context) {
        if (annoStore == null) {
            annoStore = new LocalAnnoStore(traceHandler, context);
        }
        return annoStore;
    }

    /**
     * Constructor - create a DatabaseMessageStore to store arrived MQTT message
     *
     * @param traceHandler our traceHandler
     * @param context      a context to use for android calls
     */
    private LocalAnnoStore(MqttTraceHandler traceHandler, Context context) {
        // new a empty handle for it
        if (traceHandler == null) {
            traceHandler = new MqttTraceHandler() {
                @Override
                public void traceDebug(String source, String message) {
//                    Log.d(source, message);
                }

                @Override
                public void traceError(String source, String message) {
//                    Log.e(source, message);
                }

                @Override
                public void traceException(String source, String message, Exception e) {
//                    Log.e(source, message, e);
                }
            };
        }
        this.traceHandler = traceHandler;

        // Open message database
        annoDb = new MQTTDatabaseHelper(traceHandler, context);

        traceHandler.traceDebug(TAG, "DatabaseAnnoStore<init> complete");
    }

    public boolean store(HxAnnoModel anno) {
        if (anno == null) {
            throw new RuntimeException("You cannot replace a empty anno!");
        }

        db = annoDb.getWritableDatabase();
        traceHandler.traceDebug(TAG, "replace{" + anno + "}");

        final ContentValues values = storeAnno(anno);

        try {
            db.replace(ANNO_TABLE_NAME, null, values);
        } catch (SQLException e) {
            traceHandler.traceException(TAG, "onStore", e);
            return false;
        }

        traceHandler.traceDebug(TAG, "replace anno with id of {" + anno.bulletinId + "}");

        return true;
    }

    /**
     * 设置为已读
     */
    public void updateRead() {
        db = annoDb.getWritableDatabase();
        traceHandler.traceDebug(TAG, "updateRead");
        int rows;
        final ContentValues contentValues = new ContentValues();
        contentValues.put(MQTTDatabaseHelper.READ, 0);
        try {
            rows = db.update(ANNO_TABLE_NAME, contentValues, MQTTDatabaseHelper.RECV + "=?",
                    new String[]{CLIENT_ID});
        } catch (SQLException e) {
            traceHandler.traceException(TAG, "updateRead", e);
            throw e;
        }
        traceHandler.traceDebug(TAG, "updateRead message from database: Rows affected = " + rows);
    }

    /**
     * 获取未读消息
     *
     * @param read 0表示已读、1表示未读、2表示全部
     * @return will return 0 if not found
     */
    public int getCount(int read) {
        int count = 0;
        final String[] projection = {
                MQTTDatabaseHelper.ID,
        };
        final String selection;
        final String[] selectionArgs;
        if (read == 0 || read == 1) {
            selection = MQTTDatabaseHelper.READ + "=? and " + MQTTDatabaseHelper.RECV + "=?";
            selectionArgs = new String[2];
            selectionArgs[0] = "" + read;
            selectionArgs[1] = CLIENT_ID;
        } else {
            selection = MQTTDatabaseHelper.RECV + "=?";
            selectionArgs = new String[]{CLIENT_ID};
        }
        db = annoDb.getWritableDatabase();
        Cursor c = db.query(
                ANNO_TABLE_NAME, // Table Name
                projection, // The columns to return;
                selection, // Columns for WHERE Clause
                selectionArgs, // The values for the WHERE Cause
                null,  //Don't group the rows
                null,  // Don't filter by row groups
                null   // The sort order
        );

        if (c.moveToFirst()) {
            count = c.getCount();
        }
        c.close();
        return count;
    }

    /**
     * @param count 最大数量，小于0则默认为最大
     * @return
     */
    public Iterator<HxAnnoModel> getMessages(final int count) {
        return new Iterator<HxAnnoModel>() {
            private Cursor c;
            private boolean hasNext;
            private int max;
            private int current;
            //接收以及发送

            {
                max = count < 0 ? Integer.MAX_VALUE : count;
                current = 0;
                db = annoDb.getWritableDatabase();
                // 根据发送时间降序排列
                c = db.query(ANNO_TABLE_NAME,
                        null,
                        MQTTDatabaseHelper.RECV + "=?",
                        new String[]{CLIENT_ID},
                        null,
                        null,
                        MQTTDatabaseHelper.DATE + " DESC");
                hasNext = c.moveToFirst();
            }

            @Override
            public boolean hasNext() {
                if (hasNext == false) {
                    c.close();
                }
                return hasNext;
            }

            @Override
            public HxAnnoModel next() {
                final HxAnnoModel message = createAnno(c);
                current++;
                // move on
                hasNext = c.moveToNext() && current < max;
                return message;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }

            /* (non-Javadoc)
             * @see java.lang.Object#finalize()
             */
            @Override
            protected void finalize() throws Throwable {
                c.close();
                super.finalize();
            }

        };
    }

    public void clearAll() {
        db = annoDb.getWritableDatabase();
        int rows = 0;
        try {
            traceHandler.traceDebug(TAG, "clearAnno: clearing the table");
            rows = db.delete(ANNO_TABLE_NAME, MQTTDatabaseHelper.RECV + "=?",
                    new String[]{CLIENT_ID});
        } catch (Exception e) {
            e.printStackTrace();
        }
        traceHandler.traceDebug(TAG, "clearAnno: rows affected = " + rows);
    }

    public void close() {
        if (this.db != null)
            this.db.close();
    }

    private HxAnnoModel createAnno(final Cursor c) {
        HxAnnoModel model = new HxAnnoModel();
        model.bulletinId = c.getInt(c.getColumnIndex(MQTTDatabaseHelper.ID));
        model.title = c.getString(c.getColumnIndex(MQTTDatabaseHelper.TITLE));
        model.recv = c.getString(c.getColumnIndex(MQTTDatabaseHelper.RECV));
        model.description = c.getString(c.getColumnIndex(MQTTDatabaseHelper.DESC));
        model.creater = c.getString(c.getColumnIndex(MQTTDatabaseHelper.CREATER));
        model.read = c.getInt(c.getColumnIndex(MQTTDatabaseHelper.READ));
        model.createDate = c.getLong(c.getColumnIndex(MQTTDatabaseHelper.DATE));
        return model;
    }

    private ContentValues storeAnno(final HxAnnoModel anno) {
        ContentValues values = new ContentValues();
        values.put(MQTTDatabaseHelper.ID, anno.bulletinId);
        values.put(MQTTDatabaseHelper.TITLE, anno.title);
        values.put(MQTTDatabaseHelper.DESC, anno.description);
        values.put(MQTTDatabaseHelper.RECV, anno.recv);
        values.put(MQTTDatabaseHelper.CREATER, anno.creater);
        values.put(MQTTDatabaseHelper.READ, anno.read);
        values.put(MQTTDatabaseHelper.DATE, anno.createDate);
        return values;
    }
}
